package com.lagou.edu.factory;

import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.reflections.Reflections;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author 应癫
 *
 * 工厂类，生产对象（使用反射技术）
 */
public class BeanFactory {

    /**
     * 任务一：读取解析xml，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String,Object> map = new HashMap<>();  // 存储对象

    static {
        try {
            // 开始解析@Service、@Autowired、@Transactional注解
            // 1.扫描指定包下使用了@Service注解的类
            Reflections f = new Reflections("com.lagou.edu");
            Set<Class<?>> serviceAnnotationClass = f.getTypesAnnotatedWith(Service.class);
            // 2.获取@Service的value属性，没有则默认为类名小写，记为BeanId
            for (Class<?> annotationClass : serviceAnnotationClass) {
                System.out.println("使用了@Service的类:" + annotationClass.getName());
                Service[] services = annotationClass.getAnnotationsByType(Service.class);
                String beanId = services[0].value();
                if ("".equals(beanId)) {
                    String name = annotationClass.getSimpleName();
                    String s = name.substring(0, 1);
                    beanId = name.replaceFirst(s, s.toLowerCase());
                }
                Object o = annotationClass.newInstance();
                // 3.以BeanId为key，通过反射床架你的对象为value，放入map中
                map.put(beanId, o);
            }
            // 4.遍历map，获取@Autowired注解的属性，通过反射设置注入的对象
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();
                Object value = entry.getValue();
                Class<?> valueClass = value.getClass();
                Field[] fields = valueClass.getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);
                    // 5. 如果该属性使用了Autowired注解，则准备注入
                    if (field.isAnnotationPresent(Autowired.class)) {
                        // 6.通过反射调用set方法
                        String name = field.getName();
                        String s = name.substring(0, 1);
                        String methodName = "set" + name.replaceFirst(s, s.toUpperCase());
                        Method method = valueClass.getDeclaredMethod(methodName, field.getType());
                        method.setAccessible(true);
                        Object o = map.get(name);
                        method.invoke(value, o);
                    }
                }
                // 7.将处理后的对象重新set到map中
                map.put(key, value);
            }

            // 8.以上bean才初始化完成，下面可以进行创建代理对象的操作
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();
                Object value = entry.getValue();
                Class<?> valueClass = value.getClass();
                // 9. 判断是否需要创建代理对象，需要判断bean是否是service层、并且是否使用了Transactional注解
                String packageName = valueClass.getPackageName();
                Method[] methods = valueClass.getMethods();
                boolean flag = false;
                for (Method method : methods) {
                    if (method.isAnnotationPresent(Transactional.class)) {
                        flag = true;
                    }
                }
                if ("com.lagou.edu.service.impl".equals(packageName) && flag) {
                    // 10.判断使用jdk动态代理还是cglib代理
                    Class<?>[] interfaces = valueClass.getInterfaces();
                    ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                    if (interfaces.length > 0) {
                        Object proxyFactoryJdkProxy = proxyFactory.getJdkProxy(value);
                        map.put(key, proxyFactoryJdkProxy);
                    } else {
                        Object cglibProxy = proxyFactory.getCglibProxy(value);
                        map.put(key, cglibProxy);
                    }
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static  Object getBean(String id) {
        return map.get(id);
    }

}
